﻿Imports System.IO.IsolatedStorage
Imports LSW.WP8.Extension
Imports System.IO

Namespace IO
    Public Class Cache
        Public Shared ReadOnly NoAbsoluteExpiration As Date = Date.MaxValue
        Public Shared ReadOnly NoSlidingExpiration As TimeSpan = TimeSpan.Zero

        ReadOnly _myStore As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication

        Private _sync As New Object

        Private Shared _current As Cache
        ''' <summary>
        ''' Gets the current instance of the cache
        ''' </summary>
        ''' <value>The current.</value>
        Public Shared ReadOnly Property Current As Cache
            Get
                Return If(_current, _current.InlineAssignHelper(New Cache))
            End Get
        End Property

        Public Sub Add(Of T)(key As String, value As T, ae As Date, se As TimeSpan)
            SyncLock _sync
                If Contains(key) Then
                    Remove(key)
                End If
                If ae = NoAbsoluteExpiration Then
                    Add(key, DateTime.UtcNow + se, value)
                End If
                If se = NoSlidingExpiration Then
                    Add(key, ae, value)
                End If
            End SyncLock
        End Sub

        Private Sub Add(Of T)(key As String, ed As Date, value As T)
            SyncLock _sync
                If Not _myStore.DirectoryExists(key) Then
                    _myStore.CreateDirectory(key)
                Else
                    Remove(key)
                    _myStore.CreateDirectory(key)
                End If

                Dim fileName = String.Format("{0}\{1}.cache", key, ed.ToFileTimeUtc())

                If _myStore.FileExists(fileName) Then
                    _myStore.DeleteFile(fileName)
                End If

                value.NormalWrite(fileName)
            End SyncLock
        End Sub

        Public Function Contains(key As String) As Boolean
            SyncLock _sync
                If _myStore.DirectoryExists(key) AndAlso GetFileNames(key).Any Then
                    Dim currentFile = GetFileNames(key).FirstOrDefault
                    If currentFile IsNot Nothing Then
                        Dim ed = Date.FromFileTimeUtc(Long.Parse(Path.GetFileNameWithoutExtension(currentFile)))
                        If ed <= Date.UtcNow Then
                            Return True
                        End If
                    End If
                End If
                Return False
            End SyncLock
        End Function

        Private Function GetFileNames(key As String) As IEnumerable(Of String)
            Return _myStore.GetFileNames(String.Format("{0}\*.cache", key))
        End Function

        Public Sub Remove(key As String)
            SyncLock _sync
                If Not Contains(key) Then
                    Throw New AccessViolationException("The key does not exist in the cache")
                End If
                Dim currentFile = GetFileNames(key).FirstOrDefault
                If currentFile IsNot Nothing Then
                    _myStore.DeleteFile(String.Format("{0}\{1}", key, currentFile))
                End If
                _myStore.DeleteDirectory(key)
            End SyncLock
        End Sub

        Public Function GetValue(Of T)(key As String) As T
            SyncLock _sync
                Dim currentFile = GetFileNames(key).FirstOrDefault
                If currentFile IsNot Nothing Then
                    If Contains(key) Then
                        Return NormalRead(Of T)(String.Format("{0}\{1}", key, currentFile))
                    End If
                    Remove(key)
                End If
                Return Nothing
            End SyncLock
        End Function
    End Class
End Namespace